//
//  BLHttpRequest.swift
//  BLHttpRequestDemo
//
//  Created by cgw on 2020/8/17.
//  Copyright © 2020 bill. All rights reserved.
//

import Foundation
import Alamofire

typealias BLCompleteCallback = (Any?, NSError?) -> Void

class BLHttpRequest: NSObject {
    
    enum Method {
        case GET
        case POST
        case PUT
        case DELETE
    }
    
    static let sharedInstance: BLHttpRequest = {
        return BLHttpRequest()
    }()
    
    /// 请求数据
    /// - Parameters:
    ///   - url: 接口地址
    ///   - parameters: 参数
    ///   - caller: 调用方
    ///   - isJsonType: 是否是json数据格式
    ///   - method: http方式
    ///   - complete: 完成回调
    /// - Returns: 无
    func request(url: String, parameters: [String:String]?, caller: Any, isJsonType: Bool = false, method: Method, requestModifier:Session.RequestModifier?, complete:@escaping (Data?, NSError?) -> Void) {
        let req = self.generateRequest(url: url, parameters: parameters, isJsonType: isJsonType, method: method, requestModifier:requestModifier)
        
        self.requestResponse(req: req, url: url, parameters: parameters, method: method, complete: complete)
    }
    
    enum FileType {
        case Image
        case Audio
        case Video
    }
    
    func uploadImgs(url: String, filePaths:[Any], para: [String:String]?,  requestModifier:Session.RequestModifier?, complete:@escaping (Data?, NSError?) -> Void) {
        let req =
        AF.upload(multipartFormData: { (multiPartData) in
            do {
                //上传的文件名
                var name = "file";//@"syPic";
                if url.contains("product/SyPic360/uploadWork") {
                    //上传作品
                    name = "syPic"
                }
                    
                    
                else if url.contains("user/member/uploadAddWaterMark"){
                    //上传水印图片
                    name = "upfile"
                }
                
                else if url.contains("user/member/uploadAvatar") {
                    ///上传头像
                    name = "avatar"
                }
                
                for path in filePaths {
                    var data: Data?
                    if path is String {
                        let p = path as! String
                        let url = URL.init(fileURLWithPath: p)
                        data = try Data.init(contentsOf:url)
                    }else if path is UIImage {
                        let img = path as! UIImage
                        data = img.jpegData(compressionQuality: 1.0)
                    }
                    
                    if data == nil {continue}
                    
                    let fileName = String.init(describing: NSDate())+".jpg"
                    multiPartData.append(data!, withName: name, fileName: fileName, mimeType: "image/jpeg")
                }
                
                if let para = para {
                    for (key, value) in para {
                        if let da = value.data(using: .utf8) {
                            multiPartData.append(da, withName: key)
                        }
                    }
                }
                
            } catch {
                print("上传文件为空")
            }
        }, to: url, requestModifier: requestModifier).uploadProgress { (progress) in
            var jd: Float = 0.0
            let count = progress.totalUnitCount
            jd = Float(progress.completedUnitCount)/Float(count)
            
            print("上传进度:\(jd)")
        }
        
        self.requestResponse(req: req, url: url, parameters: para, method: Method.POST, complete: complete)
    }
    
    func uploadVideo(url: String, videoPath: String?, videoCoverPath: String?, para: [String:String]?,  requestModifier:Session.RequestModifier?, complete:@escaping (Data?, NSError?) -> Void) {
        let req =
        AF.upload(multipartFormData: { (multiPartData) in
            do {
                //上传的文件名
                let name = "video";//@"syPic";
                let fileName = "video.mp4";
                var data: Data?
                if let pa = videoPath {
                    let url = URL.init(fileURLWithPath: pa)
                    data = try Data.init(contentsOf:url)
                    
                    multiPartData.append(data!, withName: name, fileName: fileName, mimeType: "video/mp4")
                    
                    //添加封面
                    if let c = videoCoverPath {
                        let curl = URL.init(fileURLWithPath: c)
                        data = try Data.init(contentsOf:curl)
                        multiPartData.append(data!, withName: "thumbnail", fileName: "thumbnail.jpg", mimeType: "image/jpeg")
                    }
                }
                
                if let para = para {
                    for (key, value) in para {
                        if let da = value.data(using: .utf8) {
                            multiPartData.append(da, withName: key)
                        }
                    }
                }
                
            } catch {
                print("上传文件为空")
            }
        }, to: url, requestModifier: requestModifier).uploadProgress { (progress) in
            var jd: Float = 0.0
            let count = progress.totalUnitCount
            jd = Float(progress.completedUnitCount)/Float(count)
            
            print("上传进度:\(jd)")
        }
        
        self.requestResponse(req: req, url: url, parameters: para, method: Method.POST, complete: complete)
    }
    
    func uploadAudio(url: String, audioPath: String?, audioName: String?, para: [String:String]?,  requestModifier:Session.RequestModifier?, complete:@escaping (Data?, NSError?) -> Void) {
        let req =
        AF.upload(multipartFormData: { (multiPartData) in
            do {
                //上传的文件名
                let name = "music";//@"syPic"; 参数名
                
                var fileName = "audio.mp3"; //文件名
                if let au = audioName {
                    fileName = au + ".mp3"
                }
                
                var data: Data?
                if let pa = audioPath {
                    let url = URL.init(fileURLWithPath: pa)
                    data = try Data.init(contentsOf:url)
                    
                    multiPartData.append(data!, withName: name, fileName: fileName, mimeType: "audio/*")
                }
                
                if let para = para {
                    for (key, value) in para {
                        if let da = value.data(using: .utf8) {
                            multiPartData.append(da, withName: key)
                        }
                    }
                }
                
            } catch {
                print("上传文件为空")
            }
        }, to: url, requestModifier: requestModifier).uploadProgress { (progress) in
            var jd: Float = 0.0
            let count = progress.totalUnitCount
            jd = Float(progress.completedUnitCount)/Float(count)
            
            print("上传进度:\(jd)")
        }
        
        self.requestResponse(req: req, url: url, parameters: para, method: Method.POST, complete: complete)
    }
    
    func download(url: String, toDir:String, fileName:String? = nil, requestModifier:Session.RequestModifier?, progressBlock:@escaping (((Progress)->Void)), complete:@escaping (String?, NSError?) -> Void) {
        
        let downDestination: DownloadRequest.Destination = { url1, _ in
//            let filename = "Alamofire_\(url.lastPathComponent)"
//            let destination = url.deletingLastPathComponent().appendingPathComponent(filename)
//
            let path = toDir//String.photoWorkTmpMaskPath()
//            let fn = (url as NSString).lastPathComponent
            var fn = url.lastFilePath()
            if let fileName = fileName {
                fn = fileName
            }
            let filePath = (path as NSString).appendingPathComponent(fn)
            let fileurl = URL.init(fileURLWithPath: filePath)
            print("下载路径：\(filePath)")
            return (fileurl, [])
        }
        
        let req =
        AF.download(url, to:downDestination).downloadProgress { (progress) in
            var jd: Float = 0.0
            let count = progress.totalUnitCount
            
            jd = Float(progress.completedUnitCount)/Float(count)
            
            print("下载进度:\(jd)")
            progressBlock(progress)
        }
        
        req.response { response in

            var err: NSError?
            if let e = response.error {
                err = NSError.init(domain: "BLHttpRequest", code: -1, userInfo: ["errkey": e])
            }
            
            let d : String = "- -"
            var header = ["-":"-"]
            if let hea = req.request?.allHTTPHeaderFields{
                header = hea
            }

            let para = ["-":"-"]
            print("\n==============Request==============\n\nRequest Url: \n\n \(url)\n\n-----------------------------\nRequest Parameters: \n\n \(String(describing: para))\n\n-----------------------------\nRequest Method: \n\n POST\n\n-----------------------------\nRequest Headers: \n\n \(String(describing: header))\n\n-----------------------------\nRequest Datas: \n\n \(d))\n\n==================================")
            let filePath = response.fileURL?.toPath() ?? ""
            print("下载完成，路径：\n"+filePath)
            complete(filePath, err)
        }
    }
    
    func cancleAllRequest() {
        AF.cancelAllRequests()
    }
    
    private func requestResponse(req: DataRequest, url: String, parameters: [String:String]?, method: Method, complete:@escaping (Data?, NSError?) -> Void) {
    
        req.responseString { response in
            
            if response.response == nil {
                //0 说明请求取消
                return;
            }
            
            if let cde = response.response?.statusCode{
                
                if cde == 401 {
                    //说明授权失败，需要重新登录
                    print("请重新登录----")
//                    Req.removeUserModel()
                    complete(nil, BLError.error(msg: "登录过期，请重新登录"))
                    return;
                }
            }
            
           var err: NSError?
           if let e = response.error {
               err = NSError.init(domain: "BLHttpRequest", code: -1, userInfo: ["errkey": e])
           }
           
           var d : String = "no data"
           if let data = response.data {
               d = String(data: data, encoding: .utf8) ?? "nodata"
           }
           
           var header = ["-":"-"]
           if let hea = req.request?.allHTTPHeaderFields{
               header = hea
           }
           
           var para = ["-":"-"]
           if let p = parameters {
               para = p
           }
           print("\n==============Request==============\n\nRequest Url: \n\n \(url)\n\n-----------------------------\nRequest Parameters: \n\n \(String(describing: para))\n\n-----------------------------\nRequest Method: \n\n \(method)\n\n-----------------------------\nRequest Headers: \n\n \(String(describing: header))\n\n-----------------------------\nRequest Datas: \n\n \(d))\n\n==================================")
           
           
           complete(response.data, err)
       }
    }
    
    private func generateRequest(url: String, parameters: [String:String]?, isJsonType: Bool, method: Method, requestModifier:Session.RequestModifier?) -> DataRequest {
        
        let headers = HTTPHeaders.init(
            ["test":"1",
             "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0"])
        
        let httpMethod = self.httpMethod(method: method)
        if isJsonType {
            let req = AF.request(url, method: httpMethod, parameters: parameters, encoder: JSONParameterEncoder.default, headers: headers, interceptor: nil, requestModifier: requestModifier)
            return req
        }else{
            let req = AF.request(url, method: httpMethod, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default, headers: headers, interceptor: nil, requestModifier: requestModifier)
            return req
        }
    }
    
    private func httpMethod(method: Method) -> HTTPMethod {
        switch method {
        case .GET:
            return HTTPMethod.get
        case .POST:
            return HTTPMethod.post
        case .PUT:
            return HTTPMethod.put
        case .DELETE:
            return HTTPMethod.delete
        }
    }
}


extension String{
    
    /// 得到路径的最后一个文件名和拓展名。
    /// 若不是以文件名结尾的。则取？分割的前半部分
    /// - Returns: Eg: 1.png
    func lastFilePath() -> String{
        let str = self
        if str.contains("?") {
            let arr = str.components(separatedBy: "?")
            if arr.count > 0 {
                let nstr = arr[0]
                return (nstr as NSString).lastPathComponent
            }
        }
        
        return (str as NSString).lastPathComponent
    }
    
    func pathExt() -> String? {
        let lp = self.lastFilePath()
        let arr = lp.components(separatedBy: ".")
        if arr.count == 2 {
            return arr.last
        }
        return nil
    }
}


extension NSObject{
    
    /*
     示例：
     d = self.datasWithArr(arr:arr, modelName:"KJSpecialCategoryModel",dicToModelSelector:"modelWithDic:")
     */
    func datasWithArr(arr: Any?, modelName: String, dicToModelSelector: String) -> [Any]? {
        
        func swiftClassFromString(className: String) -> AnyClass! {
            // get the project name
            if  let appName: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String? {
                // YourProject.className
                let classStringName = appName + "." + className
                return NSClassFromString(classStringName)
            }
            return nil;
        }
        
        guard arr != nil else {
            return nil
        }
        
        if arr! is [Dictionary<String, Any>] == false {
            return nil
        }
        
        let arr = arr as! [Dictionary<String, Any>]
        if arr.isEmpty==false {
            
            let sel = NSSelectorFromString(dicToModelSelector)
            let cls: AnyClass? = swiftClassFromString(className: modelName)//NSClassFromString(modelName)
            
            if let cls = cls {
                let c = cls as! NSObject.Type
                if c.responds(to: sel) {
                    var datas = [Any]()
                    
                    for dic in arr {
                        let m = c.perform(sel,with: dic)?.takeUnretainedValue()
                        if let model = m {
                            datas.append(model)
                        }
                    }
                    
                    if datas.isEmpty == false {
                        return datas
                    }
                }
            }
        }
        
        return nil
    }
    
    func datasWithDic(dic: Any?, dataKey: String, modelName: String, dicToModelSelector: String) -> Any? {
        
        if dic == nil {
            return nil
        }
        
        let cdic = dic!
        
        var tdic : Dictionary<String, Any>
        if cdic is Dictionary<String, Any> {
            tdic = (cdic as! Dictionary<String, Any>)
        }
        else{
            return nil
        }
        
        let arr = tdic[dataKey]
        guard arr != nil else {
            return nil
        }
        return self.datasWithArr(arr: arr!, modelName: modelName, dicToModelSelector: dicToModelSelector)
    }
    
    
}
